﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;
using Microsoft.ResourceManagement.Client;
using Microsoft.ResourceManagement.ObjectModel;
using Microsoft.ResourceManagement.ObjectModel.ResourceTypes;

namespace SampleApplication
{
    class Program
    {
        /// <summary>
        /// Use this test case as an example of normal usage of the Default Client.
        /// 
        /// Then use the Default Client source code for an example of normal usage of the underlying WsTransfer client.
        /// </summary>
        static void Main(string[] args)
        {
            // First need to construct the client
            // We will assume all default contracts
            DefaultClient client = new DefaultClient();
            // We set the client credentials since often the test cases or client apps run under different accounts
            //client.ClientCredential = Credential.GetAdminCredential();
            // We refresh the schema so that the web service put operations are better informed
            client.RefreshSchema();

            // first we want to get all existing group objects
            List<RmGroup> groups = new List<RmGroup>();
            foreach (RmResource resource in client.Enumerate("/Group"))
            {
                // Check that the cast to group works
                RmGroup group = resource as RmGroup;
                Assert.IsNotNull(group, "resource is group");

                // Check that the cast to user doesn't work
                RmPerson user = resource as RmPerson;
                Assert.IsNull(user, "resource is not person");

                // Add the group to the list of groups
                groups.Add(group);

                Console.WriteLine(group.DisplayName);
            }

            Console.WriteLine("Press enter to exit...");
            Console.ReadLine();
            return;

            RmReference domainConfigurationReference = null;
            foreach (RmResource domainConfiguration in client.Enumerate("/DomainConfiguration"))
            {
                if (domainConfiguration.DisplayName.ToLowerInvariant().Equals(Credential.GetDomain().ToLowerInvariant()))
                {
                    domainConfigurationReference = domainConfiguration.ObjectID;
                }
            }

            Assert.IsNotNull(domainConfigurationReference, "Domain Configuration exists");

            // Ensure there is a group
            if (groups.Count == 0)
            {
                RmGroup group = new RmGroup();
                group.DisplayName = System.IO.Path.GetRandomFileName();
                group.MailNickname = System.IO.Path.GetRandomFileName();
                group.Domain = Credential.GetDomain();
                group.Owner = new RmReference(Credential.GetAdminGuid());
                group.DisplayedOwner = new RmReference(Credential.GetAdminGuid());
                group.MembershipLocked = false;
                group[RmGroup.AttributeNames.MembershipAddWorkflow] = new RmAttributeValue("Owner Approval");
                group.Type = RmGroupType.Distribution;
                group.Scope = RmGroupScope.Universal;
                group[RmGroup.AttributeNames.DomainConfiguration] = new RmAttributeValue(domainConfigurationReference);
                client.Create(group);
                groups.Add(group);
            }

            // Now let's create a user
            RmPerson newUser = new RmPerson();
            // notice how built-in attributes are promoted as public properties with simple .NET types
            newUser.AccountName = System.IO.Path.GetRandomFileName();
            newUser.DisplayName = System.IO.Path.GetRandomFileName();
            newUser.FirstName = System.IO.Path.GetRandomFileName();
            newUser.LastName = System.IO.Path.GetRandomFileName();
            newUser.EmployeeID = System.IO.Path.GetRandomFileName();
            newUser.Domain = Credential.GetDomain();

            // we also can access all attributes using the dictionary interface
            newUser["MailNickname"] = new RmAttributeValue(newUser.AccountName);

            // and can access and set localized values
            // RmAttributeName chineseAttributeName = new RmAttributeName("DisplayName", new System.Globalization.CultureInfo("zh-HANS"));
            // newUser[chineseAttributeName] = new RmAttributeValue(newUser.AccountName);

            // Create the new user
            RmReference newUserId = client.Create(newUser);

            // Get the object we just created
            RmResource newUserOnServer = client.Get(newUserId);

            // we add ourselves as members to each group
            foreach (RmGroup group in groups)
            {
                // Need a transaction to watch changes to the group
                using (RmResourceChanges transaction = new RmResourceChanges(group))
                {
                    transaction.BeginChanges();
                    // We add the new user as a member in the group
                    group.ExplicitMember.Add(newUserOnServer.ObjectID);
                    try
                    {
                        // We commit the change to the server
                        client.Put(transaction);
                    }
                    catch (System.ServiceModel.FaultException<Microsoft.ResourceManagement.Client.Faults.AuthorizationRequiredFault> authZfault)
                    {
                        // Remember, AuthN and AuthZ workflows lead to SOAP faults
                        Assert.IsTrue(authZfault.Reason.ToString().Equals("Permission is required"));
                    }
                    catch (System.ServiceModel.FaultException otherFault)
                    {
                        Assert.Fail(otherFault.Reason.ToString());
                    }
                    // Show that transaction objects can be accepted during intermediate steps
                    transaction.AcceptChanges();

                    // We need to reset the change list if we plan to make additional changes.
                    // Note that we don't need a new RmResourceChanges object.
                    transaction.BeginChanges();
                    // Now we change another attribute, like DisplayName, to illustrate transactions
                    group.DisplayName = System.IO.Path.GetRandomFileName();
                    // The client only sends a put request for changes made since the last AcceptChanges() call.
                    client.Put(transaction);
                }
            }

            // We delete our new object
            client.Delete(newUserOnServer.ObjectID);
            // The state is completely cleaned up as all references are also removed.
        }
    }

    public class Assert
    {
        public static void Fail(String message)
        {
            Console.WriteLine(message);
            throw new Exception(message);
        }

        public static void IsNull(Object obj, String message)
        {
            if (obj as object != null)
            {
                Console.WriteLine(message);
                throw new Exception(message);
            }
        }

        public static void IsNotNull(Object obj, String message)
        {
            if (obj as Object == null)
            {
                Console.WriteLine(message);
                throw new Exception(message);
            }
        }

        public static void IsTrue(bool result)
        {
            if (result == false)
                throw new Exception("Result is false");
        }
    }

    public class Credential
    {
        public static System.Net.NetworkCredential GetAdminCredential()
        {
            return new System.Net.NetworkCredential("Administrator", "Pass@word1", "fabrikam");
        }
        public static System.Net.NetworkCredential GetUserCredential()
        {
            return new System.Net.NetworkCredential("Administrator", "Pass@word1", "fabrikam");
        }
        public static String GetAdminGuid()
        {
            return "7fb2b853-24f0-4498-9534-4e10589723c4";
        }

        public static String GetDomain()
        {
            return "fabrikam";
        }
    }
}
